#include "../inc/PageCache.h"
#include <cstring>
// #include <sys/mman.h>

using namespace std;

namespace memoryPoolV3 {
void *PageCache::allocateSpan(size_t numPages) {
    lock_guard<mutex> lock(mutex_);

    // 查找合适的空闲span
    // lower_bound: 返回第一个大于等于numPages的元素的迭代器
    auto it = freeSpans_.lower_bound(numPages);
    if (it != freeSpans_.end()) {
        Span *span = it->second;

        // 从空闲链表移除取出的span
        if (span->next)
            freeSpans_[it->first] = span->next;
        else
            freeSpans_.erase(it);

        if (span->numPages > numPages) { // 大于需要的numpages, 需要分割
            Span *newSpan = new Span;
            newSpan->pageAddr = static_cast<char *>(span->pageAddr) + numPages * PAGE_SIZE;

            newSpan->numPages = span->numPages - numPages;
            newSpan->next = nullptr;

            // 超出部分放回空闲链表
            auto &list = freeSpans_[newSpan->numPages];
            newSpan->next = list;
            list = newSpan;

            span->numPages = numPages;
        }

        spanMap_[span->pageAddr] = span;
        return span->pageAddr;
    }

    // 没有合适的span，申请
    void *mem = systemAlloc(numPages);
    if (!mem)
        return nullptr;

    // 创建新的span
    Span *span = new Span;
    span->pageAddr = mem;
    span->numPages = numPages;
    span->next = nullptr;

    spanMap_[mem] = span;
    return mem;
}

void PageCache::deallocateSpan(void *ptr, std::size_t numPages) {
    lock_guard<mutex> lock(mutex_);

    // 查找对应span，没找到代表不是PageCache分配的内存，返回
    auto it = spanMap_.find(ptr);
    if (it == spanMap_.end())
        return;

    Span *span = it->second;

    // 尝试合并相邻span
    void *nextAddr = static_cast<char *>(ptr) + numPages * PAGE_SIZE;
    auto nextIt = spanMap_.find(nextAddr);

    if (nextIt != spanMap_.end()) {
        Span *nextSpan = nextIt->second;

        // 检查是否在空闲链表中
        bool found = false;
        auto &nextList = freeSpans_[nextSpan->numPages];

        if (nextList == nextSpan) { // 是头节点
            nextList = nextSpan->next;
            found = true;
        } else if (nextList) {
            Span *prev = nextList;
            while (prev->next) {
                if (prev->next == nextSpan) {
                    prev->next = nextSpan->next;
                    found = true;
                    break;
                }
                prev = prev->next;
            }
        }

        if (found) { // 找到nextSpan
            span->numPages += nextSpan->numPages;
            spanMap_.erase(nextAddr);
            delete nextSpan;
        }
    }

    auto &list = freeSpans_[span->numPages];
    span->next = list;
    list = span;
}

void *PageCache::systemAlloc(size_t numPages) {
    std::size_t size = numPages * PAGE_SIZE;

    // 使用mmap分配内存
    void *ptr = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);

    if (ptr == MAP_FAILED)
        return nullptr;

    // 内存清零
    memset(ptr, 0, size);
    return ptr;
}

} // namespace memoryPoolV3